#ifndef MEMORY_H
#define MEMORY_H

#include "main.h"
#include "structs.h"
#include "panic.h"
#include "lock.h"

#define ALLOC_HEADER_MAGIC 0xBEEF
#define MEMORY_MAP_SIZE 32768

//#define AUTO_DEFRAG_MEMORY

/* Kopiert einen Speicherbereich
 * Parameter: Zielort, Quelle, Länge
 * Rückgaben: Zielbuffer
 */
void *memcpy (void *, const void *, int);

/* Füllt einen Speicherbereich
 * Parameter: Zielort, Füllzeichen, Länge
 * Rückgaben: Zielort
 */
void *memset (void *, char, int);

/* Gibt die aktuelle RAM Auslastung in Bytes zurück
* Parameter: Keine
* Rückgaben: Alloziierte Bytes insgesamt
*/
size_t get_used_memory ();

/* Markiert eine Page als frei
 * Parameter: Adresse der Page
 * Rückgaben: Keine
 */
void pmm_free (void *);

/* Findet eine freie Page, markiert diese als benutzt und gibt ihre Adresse zurück
 * Parameter: Keine
 * Rückgaben: Adresse
 */
void *pmm_alloc ();

/* Sucht mehrere freie zusammenhängende Pages und gibt bei Erfolg die Position zurück
* Parameter: Größe des angeforderten Speichers in Byte
* Rückgaben: Bei Erfolg die Position des Speichers, ansonsten NULL
*/
void *pmm_range_alloc (uint32_t);

/* Zeigt an, ob eine Page frei ist oder nicht
 * Parameter: Pagenummer
 * Rückgaben: TRUE = Page ist frei, sonst FALSE
 */
BOOL pmm_is_page_free (int);

/* Überprüft ob ein Bereich von hintereinander liegenden Pages frei ist
 * Parameter: Start Page, Anzahl
 * Rückgaben: TRUE wenn diese frei sind, ansonsten FALSE
 */
BOOL pmm_is_page_range_free (int, int);

/* Diese Funktion sucht einen zusammenhängenden Block unterhalb von 16MB im RAM für DMA Operationen
 * Parameter: Größe des Bereichs in Byte
 * Rückgaben: Zeiger auf den Bereich, ansonsten NULL
 */
void *pmm_alloc_dma (uint32_t);

/* Markiert eine Page als belegt - nur INTERN!
 * Parameter: Adresse
 * Rückgaben: Keine
 */
void pmm_mark_page_as_used (void *);

/* Markiert eine Page als belegt - nur INTERN
 * Parameter: Index, Bit
 * Rückgaben: Keine
 */
void inline pmm_mark_page_as_used_ex (size_t, size_t);

/* Startet den Memory Manager
 * Parameter: Multiboot_info Struktur von GRUB
 * Rückgaben: Keine
 */
void pmm_init (struct multiboot_info *);

/** Der folgende Code stammt von liballoc **/

#define PREFIX(func)		func

/** This function is supposed to lock the memory data structures. It
* could be as simple as disabling interrupts or acquiring a spinlock.
* It's up to you to decide. 
*
* \return 0 if the lock was acquired successfully. Anything else is
* failure.
*/
extern int liballoc_lock();

/** This function unlocks what was previously locked by the liballoc_lock
* function.  If it disabled interrupts, it enables interrupts. If it
* had acquiried a spinlock, it releases the spinlock. etc.
*
* \return 0 if the lock was successfully released.
*/
int liballoc_unlock();

/** This is the hook into the local system which allocates pages. It
* accepts an integer parameter which is the number of pages
* required.  The page size was set up in the liballoc_init function.
*
* \return NULL if the pages were not allocated.
* \return A pointer to the allocated memory.
*/
void* liballoc_alloc(size_t);

/** This frees previously allocated memory. The void* parameter passed
* to the function is the exact same value returned from a previous
* liballoc_alloc call.
*
* The integer value is the number of pages to free.
*
* \return 0 if the memory was successfully freed.
*/
int liballoc_free(void*,size_t);

void *malloc(size_t);			///< The standard function.
void *realloc(void *, size_t);		///< The standard function.
void *calloc(size_t, size_t);		///< The standard function.
void free(void *);				///< The standard function.

#endif
